﻿using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.ExtensionsAPI;
using JetBrains.ReSharper.Psi.Impl.Search.SearchDomain;
using JetBrains.ReSharper.Psi.Search;
using JetBrains.ReSharper.Psi.Xaml;
using JetBrains.Util;

namespace GammaJul.ReSharper.GammaXaml.Services.Xaml.Navigation {

	/// <summary>
	/// See <see cref="CaliburnGuardReferenceSearcher"/> for more information about why this is implemented.
	/// </summary>
	[PsiSharedComponent]
	public class CaliburnGuardSearcherFactory : IDomainSpecificSearcherFactory {

		public bool IsCompatibleWithLanguage(PsiLanguageType languageType) {
			return languageType.Is<XamlLanguage>();
		}

		public IDomainSpecificSearcher CreateConstructorSpecialReferenceSearcher(ICollection<IConstructor> constructors) {
			return null;
		}

		public IDomainSpecificSearcher CreateMethodsReferencedByDelegateSearcher(IDelegate @delegate) {
			return null;
		}

		public IDomainSpecificSearcher CreateReferenceSearcher(ICollection<IDeclaredElement> elements, bool findCandidates) {
			return new CaliburnGuardReferenceSearcher(elements, findCandidates, false);
		}

		public IDomainSpecificSearcher CreateTextOccurenceSearcher(ICollection<IDeclaredElement> elements) {
			return null;
		}

		public IDomainSpecificSearcher CreateTextOccurenceSearcher(string subject) {
			return null;
		}

		public IDomainSpecificSearcher CreateLateBoundReferenceSearcher(ICollection<IDeclaredElement> elements) {
			return new CaliburnGuardReferenceSearcher(elements, false, true);
		}

		public IDomainSpecificSearcher CreateAnonymousTypeSearcher(IList<AnonymousTypeDescriptor> typeDescription, bool caseSensitive) {
			return null;
		}

		public IDomainSpecificSearcher CreateConstantExpressionSearcher(ConstantValue constantValue, bool onlyLiteralExpression) {
			return null;
		}

		public IEnumerable<string> GetAllPossibleWordsInFile(IDeclaredElement element) {
			string nonGuardSearchName = GetNonGuardSearchName(element);
			return nonGuardSearchName == null ? EmptyArray<string>.Instance : new[] { nonGuardSearchName };
		}

		[CanBeNull]
		internal static string GetNonGuardSearchName(IDeclaredElement element) {
			if (element is IProperty || element is IMethod) {
				string shortName = element.ShortName;
				if (!String.IsNullOrEmpty(shortName) && shortName.StartsWith("Can", StringComparison.Ordinal))
					return shortName.Substring(3);
			}
			return null;
		}

		public IEnumerable<Pair<IDeclaredElement, Predicate<FindResult>>> GetRelatedDeclaredElements(IDeclaredElement element) {
			return EmptyArray<Pair<IDeclaredElement, Predicate<FindResult>>>.Instance;
		}

		public JetTuple<ICollection<IDeclaredElement>, Predicate<IFindResultReference>, bool> GetDerivedFindRequest(IFindResultReference result) {
			return null;
		}

		public JetTuple<ICollection<IDeclaredElement>, bool> GetNavigateToTargets(IDeclaredElement element) {
			return null;
		}

		public ICollection<FindResult> TransformNavigationTargets(ICollection<FindResult> targets) {
			return targets;
		}

		public ISearchDomain GetDeclaredElementSearchDomain(IDeclaredElement declaredElement) {
			return EmptySearchDomain.Instance;
		}

	}

}